package com.czk;

import com.czk.bytebuddy.MethodCostTime;
import com.czk.jvm.JvmStack;
import com.czk.track.MyAdvice;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.matcher.ElementMatchers;
import net.bytebuddy.utility.JavaModule;

import java.lang.instrument.Instrumentation;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * @Author:ChenZhangKun
 * @Date: 2021/8/5 10:53
 */
public class MyAgent {
    // JVM 首先尝试在代理类上调用以下方法
    // 执行main方法时会首先执行他
    public static void premain(String agentArgs, Instrumentation inst) {
        System.out.println("嗨！JavaAgent " + agentArgs);
        // 打印jvm信息
        Executors.newScheduledThreadPool(1).scheduleAtFixedRate(() -> {
            JvmStack.printMemoryInfo();
            JvmStack.printGcInfo();
            System.out.println("==================================");
        }, 0, 5000, TimeUnit.MILLISECONDS);


        // javaasisit计算方法耗时
        MyMonitorTransformer myMonitorTransformer = new MyMonitorTransformer();
        inst.addTransformer(myMonitorTransformer);

       // AgentBuilder agentBuilder=new AgentBuilder.Default();
        // bytebuddy计算方法耗时
        AgentBuilder.Transformer transformer = (builder, typeDescription, classLoader, javaModule) -> {
            // 这里属实现方法监控的
            return builder
                    // 拦截任一方法
                    .method(ElementMatchers.any())
                    // 委托给一个类处理
                    .intercept(MethodDelegation.to(MethodCostTime.class));
            // 这里是实现全链路追踪的
/*            return builder
                    .visit(Advice.to(MyAdvice.class)
                            .on(ElementMatchers.isMethod()
                                    .and(ElementMatchers.any()
                                            .and(ElementMatchers.not(ElementMatchers.nameStartsWith("main"))))));*/
        };
        // 基于全链路追踪
        /*agentBuilder=agentBuilder.type(ElementMatchers.nameStartsWith("com.czk")).transform(transformer).asDecorator();*/
        AgentBuilder.Listener listener = new AgentBuilder.Listener() {
            @Override
            public void onDiscovery(String s, ClassLoader classLoader, JavaModule javaModule, boolean b) {

            }

            @Override
            public void onTransformation(TypeDescription typeDescription, ClassLoader classLoader, JavaModule javaModule, boolean b, DynamicType dynamicType) {
                System.out.println("onTransformation：" + typeDescription);
            }

            @Override
            public void onIgnored(TypeDescription typeDescription, ClassLoader classLoader, JavaModule javaModule, boolean b) {

            }

            @Override
            public void onError(String s, ClassLoader classLoader, JavaModule javaModule, boolean b, Throwable throwable) {

            }

            @Override
            public void onComplete(String s, ClassLoader classLoader, JavaModule javaModule, boolean b) {

            }
        };
        // 这里是实现方法监控的·
        new AgentBuilder
                .Default()
                // 指定需要拦截的类
                .type(ElementMatchers.nameStartsWith("com.czk"))
                .transform(transformer)
                .with(listener)
                .installOn(inst);
    // 这里是实现全链路追踪的
    /*    agentBuilder
                .with(listener)
                .installOn(inst);*/
    }

    // 如果代理类没有实现上面的方法，那么 JVM 将尝试调用该方法
    public static void premain(String agentArgs) {
    }
}
